package com.gitee.wsl.coroutines.job.trigger

import com.gitee.wsl.coroutines.job.JobDataMap
import com.gitee.wsl.coroutines.job.JobKey
import kotlin.time.ExperimentalTime
import kotlin.time.Instant


@OptIn(ExperimentalTime::class)
interface ITrigger : Comparable<ITrigger> {
    enum class ETriggerState {
        NONE,
        NORMAL,
        PAUSED,
        COMPLETE,
        ERROR,
        BLOCKED
    }

    /**
     *
     *
     * `NOOP` Instructs the `[IScheduler]` that the
     * `[ITrigger]` has no further instructions.
     *
     *
     *
     * `RE_EXECUTE_JOB` Instructs the `[IScheduler]`
     * that the `[ITrigger]` wants the
     * `[com.helger.quartz.IJobDetail]` to re-execute
     * immediately. If not in a 'RECOVERING' or 'FAILED_OVER' situation, the
     * execution context will be re-used (giving the `Job` the ability
     * to 'see' anything placed in the context by its last execution).
     *
     *
     *
     * `SET_TRIGGER_COMPLETE` Instructs the
     * `[IScheduler]` that the `[ITrigger]`
     * should be put in the `COMPLETE` state.
     *
     *
     *
     * `DELETE_TRIGGER` Instructs the `[IScheduler]`
     * that the `[ITrigger]` wants itself deleted.
     *
     *
     *
     * `SET_ALL_JOB_TRIGGERS_COMPLETE` Instructs the
     * `[IScheduler]` that all `Trigger`s referencing
     * the same `[com.helger.quartz.IJobDetail]` as this one
     * should be put in the `COMPLETE` state.
     *
     *
     *
     * `SET_TRIGGER_ERROR` Instructs the
     * `[IScheduler]` that all `Trigger`s referencing
     * the same `[com.helger.quartz.IJobDetail]` as this one
     * should be put in the `ERROR` state.
     *
     *
     *
     * `SET_ALL_JOB_TRIGGERS_ERROR` Instructs the
     * `[IScheduler]` that the `Trigger` should be put
     * in the `ERROR` state.
     *
     */
    enum class ECompletedExecutionInstruction {
        NOOP,
        RE_EXECUTE_JOB,
        SET_TRIGGER_COMPLETE,
        DELETE_TRIGGER,
        SET_ALL_JOB_TRIGGERS_COMPLETE,
        SET_TRIGGER_ERROR,
        SET_ALL_JOB_TRIGGERS_ERROR
    }

    enum class EMisfireInstruction {
        /**
         * Instructs the `[IScheduler]` that the
         * `Trigger` will never be evaluated for a misfire situation, and
         * that the scheduler will simply try to fire it as soon as it can, and then
         * update the Trigger as if it had fired at the proper time.<br></br>
         * NOTE: if a trigger uses this instruction, and it has missed several of
         * its scheduled firings, then several rapid firings may occur as the
         * trigger attempt to catch back up to where it would have been. For
         * example, a SimpleTrigger that fires every 15 seconds which has misfired
         * for 5 minutes will fire 20 times once it gets the chance to fire.
         */
        MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY,  // -1

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `updateAfterMisfire()` method will be called on
         * the `Trigger` to determine the mis-fire instruction, which
         * logic will be trigger-implementation-dependent.<br></br>
         * In order to see if this instruction fits your needs, you should look at
         * the documentation for the `getSmartMisfirePolicy()` method on
         * the particular `Trigger` implementation you are using.
         */
        MISFIRE_INSTRUCTION_SMART_POLICY,  // 0

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `Trigger` wants to be fired now by
         * `Scheduler`.
         */
        MISFIRE_INSTRUCTION_FIRE_ONCE_NOW,  // 1

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `Trigger` wants to have it's next-fire-time
         * updated to the next time in the schedule after the current time (taking
         * into account any associated `Calendar`, but it does not want
         * to be fired now.<br></br>
         * Not applicable to ISimpleTrigger
         */
        MISFIRE_INSTRUCTION_DO_NOTHING,  // 2

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `[ISimpleTrigger]` wants to be
         * re-scheduled to 'now' (even if the associated
         * `[ICalendar]` excludes 'now') with the repeat count left
         * as-is. This does obey the `Trigger` end-time however, so if
         * 'now' is after the end-time the `Trigger` will not fire
         * again.<br></br>
         * *NOTE:* Use of this instruction causes the trigger to 'forget' the
         * start-time and repeat-count that it was originally setup with (this is
         * only an issue if you for some reason wanted to be able to tell what the
         * original values were at some later time).<br></br>
         * Only applicable to ISimpleTrigger
         */
        MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT,  // 2

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `[ISimpleTrigger]` wants to be
         * re-scheduled to 'now' (even if the associated
         * `[ICalendar]` excludes 'now') with the repeat count set
         * to what it would be, if it had not missed any firings. This does obey the
         * `Trigger` end-time however, so if 'now' is after the end-time
         * the `Trigger` will not fire again.<br></br>
         * *NOTE:* Use of this instruction causes the trigger to 'forget' the
         * start-time and repeat-count that it was originally setup with. Instead,
         * the repeat count on the trigger will be changed to whatever the remaining
         * repeat count is (this is only an issue if you for some reason wanted to
         * be able to tell what the original values were at some later time).<br></br>
         * *NOTE:* This instruction could cause the `Trigger` to go
         * to the 'COMPLETE' state after firing 'now', if all the repeat-fire-times
         * where missed.<br></br>
         * Only applicable to ISimpleTrigger
         */
        MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT,  // 3

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `[ISimpleTrigger]` wants to be
         * re-scheduled to the next scheduled time after 'now' - taking into account
         * any associated `[ICalendar]`, and with the repeat count
         * set to what it would be, if it had not missed any firings.<br></br>
         * *NOTE/WARNING:* This instruction could cause the
         * `Trigger` to go directly to the 'COMPLETE' state if all
         * fire-times where missed.<br></br>
         * Only applicable to ISimpleTrigger
         */
        MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT,  // 4

        /**
         * Instructs the `[IScheduler]` that upon a mis-fire
         * situation, the `[ISimpleTrigger]` wants to be
         * re-scheduled to the next scheduled time after 'now' - taking into account
         * any associated `[ICalendar]`, and with the repeat count
         * left unchanged.<br></br>
         * *NOTE/WARNING:* This instruction could cause the
         * `Trigger` to go directly to the 'COMPLETE' state if the
         * end-time of the trigger has arrived.<br></br>
         * Only applicable to ISimpleTrigger
         */
        MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT // 5
    }
    
    val key: TriggerKey?
    
    val jobKey: JobKey?
    
    val description: String?
    
    val calendarName: String?

    val jobDataMap: JobDataMap?

    /**
     * The priority of a `Trigger` acts as a tiebreaker such that if
     * two `Trigger`s have the same scheduled fire time, then the one
     * with the higher priority will get first access to a worker thread.<br></br>
     * If not explicitly set, the default value is `5`.
     *
     * @see .DEFAULT_PRIORITY
     */
    val priority: Int

    /**
     * Get the time at which the `Trigger` should occur.
     *
     * @return The start. May be `null` depending on the implementation
     */
    val startTime: Instant?


    val endTime: Instant?

    /**
     * Returns the next time at which the `Trigger` is scheduled to
     * fire. If the trigger will not fire again, `null` will be
     * returned. Note that the time returned can possibly be in the past, if the
     * time that was computed for the trigger to next fire has already arrived,
     * but the scheduler has not yet been able to fire the trigger (which would
     * likely be due to lack of resources e.g. threads).
     *
     *
     * The value returned is not guaranteed to be valid until after the
     * `Trigger` has been added to the scheduler.
     *
     *
     * @see TriggerUtils.computeFireTimesBetween
     */
    val nextFireTime: Instant?

    /**
     * Returns the previous time at which the `Trigger` fired. If the
     * trigger has not yet fired, `null` will be returned.
     */
    val previousFireTime: Instant?


    /**
     * Returns the last time at which the `Trigger` will fire, if the
     * Trigger will repeat indefinitely, null will be returned.
     *
     *
     * Note that the return time *may* be in the past.
     *
     */
    val finalFireTime: Instant?

    /**
     * Get the instruction the `Scheduler` should be given for handling
     * misfire situations for this `Trigger`- the concrete
     * `Trigger` type that you are using will have defined a set of
     * additional `MISFIRE_INSTRUCTION_XXX` constants that may be set
     * as this property's value.
     *
     *
     * If not explicitly set, the default value is
     * `MISFIRE_INSTRUCTION_SMART_POLICY`.
     *
     *
     * @see ISimpleTrigger
     *
     * @see ICronTrigger
     */
    val misfireInstruction: EMisfireInstruction?


    /**
     * Used by the `[IScheduler]` to determine whether or not it
     * is possible for this `Trigger` to fire again.
     *
     *
     * If the returned value is `false` then the `Scheduler`
     * may remove the `Trigger` from the
     * `[com.helger.quartz.spi.IJobStore]`.
     *
     */
    fun mayFireAgain(): Boolean


    /**
     * Returns the next time at which the `Trigger` will fire, after
     * the given time. If the trigger will not fire after the given time,
     * `null` will be returned.
     */
    fun getFireTimeAfter(afterTime: Instant): Instant?


    /**
     * Get a [TriggerBuilder] that is configured to produce a
     * `Trigger` identical to this one.
     *
     * @see .getScheduleBuilder
     */
    val triggerBuilder: TriggerBuilder<out ITrigger>?

    /**
     * Get a [IScheduleBuilder] that is configured to produce a schedule
     * identical to this trigger's schedule.
     *
     * @see .getTriggerBuilder
     */
    val scheduleBuilder: IScheduleBuilder<out IMutableTrigger>?

    /**
     * Compare the next fire time of this `Trigger` to that of another
     * by comparing their keys, or in other words, sorts them according to the
     * natural (i.e. alphabetical) order of their keys.
     */
    //override fun compareTo(other: ITrigger): Int


    companion object {
        /**
         * The default value for priority.
         */
        const val DEFAULT_PRIORITY: Int = 5
    }
}


fun<I:ITrigger> createTrigger(config:TriggerBuilder<I>.()->Unit):I{
    val builder = TriggerBuilder.newTrigger<I>()
    builder.config()
    return builder.build()
}